package com.example.lotapp.network;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.Socket;
import java.util.zip.GZIPInputStream;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.conn.scheme.LayeredSocketFactory;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.SingleClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;

import com.example.lotapp.network.util.NetworkUtil;

public class HttpUtils {
	private static int mConnectTimeout = 30 * 1000;
	private static int mReadTimeout = 30 * 1000;
	
	public static int TYPE_CONNECT_OUT = 0;
	public static int TYPE_CONNECT_ERROR = 1;
	public static int TYPE_CONNECT_OK = 2;
	
	public static String SERVER_URL = "http://client.jiangduoduo.com/action/MobileHandler.ashx";
	
	public static class ResponseObject {
		public int mType;
		public int mCode;
	};
	
	public static int getConnectTimeout() {
		return mConnectTimeout;
	}

	public static int getReadTimeout() {
		return mReadTimeout;
	}

	public static void setConnectTimeout(int timeout) {
		mConnectTimeout = timeout;
	}

	public static void setReadTimeout(int timeout) {
		mReadTimeout = timeout;
	}

	static private ClientConnectionManager createClientConnectionManager(HttpParams params) {
        SchemeRegistry registry = new SchemeRegistry();

        registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        workAroundReverseDnsBugInHoneycombAndEarlier(registry);

        ClientConnectionManager connectionManager = new SingleClientConnManager(params, registry);
        return connectionManager;
    }

	static public HttpClient getHttpClient() {
	    HttpParams params = new BasicHttpParams();
        ConnManagerParams.setTimeout(params, mConnectTimeout);

        HttpConnectionParams.setConnectionTimeout(params, mConnectTimeout);
        HttpConnectionParams.setSoTimeout(params, mConnectTimeout);

        ClientConnectionManager connectionManager = createClientConnectionManager(params);
        HttpClient httpClient = new DefaultHttpClient(connectionManager, params);
        return httpClient;
	}
	
	/**
	 * @param url
	 *            需要访问的网址，不能为null
	 * @return 服务端返回的字符串
	 * @throws IOException
	 */
	public static String get(String url, ResponseObject responseObject) throws IOException {
		if (url == null || !NetworkUtil.isNetworkConnected()) {
			if (responseObject != null) {
				responseObject.mType = TYPE_CONNECT_OUT;
			}
			return null;
		}
		if (responseObject != null) {
			responseObject.mType = TYPE_CONNECT_ERROR;
		}
		HttpClient httpClient = getHttpClient();
        HttpGet httpGet = new HttpGet(url);
        InputStream inputStream = null;
        boolean succeed = false;
        try {
            httpGet.setHeader("Accept-Encoding", "gzip");
            HttpResponse response = httpClient.execute(httpGet);
            if (null == response) {
                return null;
            }
            
            int responseCode = response.getStatusLine().getStatusCode();
            if (responseObject != null) {
            	responseObject.mType = TYPE_CONNECT_OK;
            	responseObject.mCode = responseCode;
            }
            if (HttpURLConnection.HTTP_OK == responseCode) {
                HttpEntity httpEntity = response.getEntity();
                inputStream = httpEntity.getContent();
                
                boolean gzip = false;
                org.apache.http.Header contentEncoding = httpEntity.getContentEncoding();
                if (contentEncoding != null) {
                    String encoding = contentEncoding.getValue();
                    gzip = encoding.contains("gzip");
                }
                succeed = true;
                return readStream(inputStream, gzip);
            } else {
                return null;
            }
        } catch (ClientProtocolException e) {
            return null;
        } finally {
            closeStream(inputStream);
            
            if (!succeed) {
                httpGet.abort();
            }
            
            ClientConnectionManager connectionManager = httpClient.getConnectionManager();
            if (connectionManager != null) {
                connectionManager.shutdown();
            }
        }
	}

	/**
	 * @param url
	 *            需要访问的网址，不能为null
	 * @param data
	 *            用&连接的字符串参数。
	 * @return 服务端返回的字符串
	 * @throws IOException
	 */
	public static String post(String url, String data, ResponseObject responseObject) throws IOException {
		if (url == null || data == null || !NetworkUtil.isNetworkConnected()) {
			if (responseObject != null) {
				responseObject.mType = TYPE_CONNECT_OUT;
			}
			return null;
		}
		
		if (responseObject != null) {
			responseObject.mType = TYPE_CONNECT_ERROR;
		}
        HttpClient httpClient = getHttpClient();
        HttpPost httpPost = new HttpPost(url);
        InputStream inputStream = null;
        boolean succeed = false;
        try {
            httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
            httpPost.setHeader("Accept-Encoding", "gzip");
            httpPost.setEntity(new ByteArrayEntity(data.getBytes()));
            HttpResponse response = httpClient.execute(httpPost);
            if (null == response) {
                return null;
            }
            
            int responseCode = response.getStatusLine().getStatusCode();
            if (responseObject != null) {
            	responseObject.mType = TYPE_CONNECT_OK;
            	responseObject.mCode = responseCode;
            }
            
            if (HttpURLConnection.HTTP_OK == responseCode) {
                HttpEntity httpEntity = response.getEntity();
                inputStream = httpEntity.getContent();
                boolean gzip = false;
                org.apache.http.Header contentEncoding = httpEntity.getContentEncoding();
                if (contentEncoding != null) {
                    String encoding = contentEncoding.getValue();
                    gzip = encoding.contains("gzip");
                }
                succeed = true;
                return readStream(inputStream, gzip);
            } else {
                return null;
            }
        } catch (ClientProtocolException e) {
            return null;
        } finally {
            closeStream(inputStream);
            
            if (!succeed) {
                httpPost.abort();
            }
            
            ClientConnectionManager connectionManager = httpClient.getConnectionManager();
            if (connectionManager != null) {
                connectionManager.shutdown();
            }
        }
	}
	
	private static void workAroundReverseDnsBugInHoneycombAndEarlier(SchemeRegistry registry) {
        /**
         * Android had a bug where HTTPS made reverse DNS lookups (fixed in Ice Cream Sandwich)
         * http://code.google.com/p/android/issues/detail?id=13117
         */
        LayeredSocketFactory socketFactory = new LayeredSocketFactory() {
            SSLSocketFactory delegate = SSLSocketFactory.getSocketFactory();

            @Override
            public Socket createSocket() throws IOException {
                return delegate.createSocket();
            }

            @Override
            public Socket connectSocket(Socket sock, String host, int port,
                    InetAddress localAddress, int localPort,
                    HttpParams params) throws IOException {
                return delegate.connectSocket(sock, host, port,
                        localAddress, localPort, params);
            }

            @Override
            public boolean isSecure(Socket sock) throws IllegalArgumentException {
                return delegate.isSecure(sock);
            }

            @Override
            public Socket createSocket(Socket socket, String host,
                    int port, boolean autoClose) throws IOException {
                injectHostname(socket, host);
                return delegate.createSocket(socket, host, port, autoClose);
            }

            private void injectHostname(Socket socket, String host) {
                try {
                    Field field = InetAddress.class
                            .getDeclaredField("hostName");
                    field.setAccessible(true);
                    field.set(socket.getInetAddress(), host);
                } catch (Exception ignored) {
                }
            }
        };
        registry.register(new Scheme("https", socketFactory, 443));
    }

	/**
	 * @param url
	 *            需要下载的文件
	 * @param file
	 *            保存的本地文件
	 * @return 文件的大小，单位是字节。如果不成功返回-1。
	 * @throws IOException
	 */
	public static long download(String url, String file) throws IOException {
		if (url == null) {
			return -1;
		}
		
		HttpClient httpClient = getHttpClient();
        HttpGet httpGet = new HttpGet(url);
        InputStream reader = null;
        FileOutputStream writer = null;
        boolean succeed = false;
        try {
            HttpResponse response = httpClient.execute(httpGet);
            if (null == response) {
                return -1;
            }

            if (HttpURLConnection.HTTP_OK == response.getStatusLine().getStatusCode()) {
                HttpEntity httpEntity = response.getEntity();
                reader = httpEntity.getContent();
                
                writer = new FileOutputStream(file);
                long readCount = 0;
                byte[] buffer = new byte[2048];
                int count = 0;
                while ((count = reader.read(buffer)) != -1) {
                    writer.write(buffer, 0, count);
                    readCount += count;
                }
                succeed = true;
                return readCount;
            } else {
                return -1;
            }
        } catch (ClientProtocolException e) {
            return -1;
        } finally {
            closeStream(reader);
            closeStream(writer);
            
            if (!succeed) {
                httpGet.abort();
            }
            
            ClientConnectionManager connectionManager = httpClient.getConnectionManager();
            if (connectionManager != null) {
                connectionManager.shutdown();
            }
        }
	}

	/**
	 * @param url
	 *            需要下载的文件
	 * @return 文件的二进制数据
	 * @throws IOException
	 */
	public static byte[] download(String url) throws IOException {
		if (url == null) {
			return null;
		}
		
		HttpClient httpClient = getHttpClient();
        HttpGet httpGet = new HttpGet(url);
        InputStream reader = null;
        boolean succeed = false;
        try {
            HttpResponse response = httpClient.execute(httpGet);
            if (null == response) {
                return null;
            }

            if (HttpURLConnection.HTTP_OK == response.getStatusLine().getStatusCode()) {
                HttpEntity httpEntity = response.getEntity();
                reader = httpEntity.getContent();
                
                byte[] buffer = new byte[2048];
                ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
                int count = 0;
                while ((count = reader.read(buffer)) != -1) {
                    byteBuffer.write(buffer, 0, count);
                }
                return byteBuffer.toByteArray();
            } else {
                return null;
            }
        } catch (ClientProtocolException e) {
            return null;
        } finally {
            closeStream(reader);
            
            if (!succeed) {
                httpGet.abort();
            }
            
            ClientConnectionManager connectionManager = httpClient.getConnectionManager();
            if (connectionManager != null) {
                connectionManager.shutdown();
            }
        }
	}

	private static void closeStream(Closeable close) {
		if (close == null) {
			return;
		}
		try {
			close.close();
		} catch (IOException e) {

		} finally {
			close = null;
		}
	}
	
	private static String readStream(InputStream input, boolean gzip) throws IOException {
	    InputStream inputStream = null;
	    if (gzip) {
	        inputStream = new GZIPInputStream(input);
	    } else {
	        inputStream = input;
	    }
	    
        StringBuffer result = new StringBuffer();
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        
        String str = null;
        while ((str = reader.readLine()) != null) {
            result.append(str).append("\n");
        }
        return result.toString();
	}
}
